/*
 * Project.java
 * 
 * last update: 14.01.2010 by Stefan Saru
 * 
 * author:	Felix(felix@ulise.cs.pub.ro)
 *
 * Obs: N/A
 */

package ide;

import java.util.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.border.*;
import javax.swing.event.*;
//import javax.swing.plaf.*;
//import javax.swing.text.*;
//import javax.swing.tree.*;
import javax.swing.undo.*;
import javax.swing.text.Document;
import middle.*;
import engine.*;

class Project {

	public static final String PROJECT_EXTENSION = "vpr";

	protected ProjectView pv;       //referinta la ProjectView
	protected WatchView wv;         //to the bathrooom..
	protected BookmarksView bv;
	//chestie mishto frumos colorata cu butoane care merge fara 3DFX
	//nefolosita..
	public ConsoleView cv;          //referinta la consola
	protected int lastBookmark;     //not used.Err.. I don't know..
	protected VeriSimFrame god;     //Tatal Lor care e deasupra (Frame-ul aplicatiei)
	public VeriSimFrame.StatusBar sb;
	public WaveViewFrame waveViewFrame;
	public VeriSimDocumentFrame focusedEditor;  //editorul curent //activeEditor era mai potrivit
	public boolean isValid;         //un proiect este incarcat
	public static EmptyIcon emptyIcon = new EmptyIcon(17, 17);   
	//o icoana plina cu goluri


	/**
	 * this contains _only_ the files that are included into
	 * the current project
	 */
	protected HashSet files;

	/**
	 * The open VeriSimDocumentFrames
	 */
	protected Hashtable editors;

	/**
	 * Contains (fileName , Document)
	 * pairs.
	 */
	protected Hashtable documents;

	protected Hashtable bookmarks;  //lacul cu prune
	protected String name, path;          // /home/Bill Clinton
	//protected File directory;     //project directory //not used  //yet?
	javax.swing.tree.DefaultMutableTreeNode watchTreeRoot;
	//public JProgressBar pb;       //not used
	//  public BusyFlag bf;             //shows an animation and a explanation for the current action
	public VCDReader vcdReader;     //folosit la WaveView
	//furnizeaza istoria variabilelor.

	static Hashtable dictionaries = new Hashtable();  
	//pentru sintax-highligth

	//variabile folosite in operatia de cautare a unui text in editor
	public int fromWhereToFind = 0;
	public String textToFind = new String("BulaXYZ");
	//daca un fisier contzine BulaXYZ, cautarea va da gres... (pe bune!)


	ThreadGroup simulationThreadGroup = new ThreadGroup("Simulation");
	//pentru un control sigur(?!) al mizeriei produse de simulator 
	/*
	 *  File actions
	 */

	public AbstractAction newAction = new NewAction();
	public AbstractAction openAction = new OpenAction();
	public AbstractAction closeAction = new CloseAction();

	public AbstractAction newProjectAction = new NewProjectAction();
	public AbstractAction openProjectAction = new OpenProjectAction();
	public AbstractAction saveProjectAction = new SaveProjectAction();
	public AbstractAction closeProjectAction = new CloseProjectAction();
	public AbstractAction revertToSavedAction = new RevertToSavedAction();

	public AbstractAction addFilesToProjectAction = new AddFilesToProjectAction();
	public AbstractAction removeCurrentFileFromProject = new RemoveCurrentFileFromProject();

	public AbstractAction saveAction = new SaveAction();
	public AbstractAction saveAsAction = new SaveAsAction();
	public AbstractAction saveAllAction = new SaveAllAction();

	public AbstractAction printAction = new PrintAction();
	public AbstractAction printSetupAction = new PrintSetupAction();

	public AbstractAction quitAction = new QuitAction();


	/*
	 *  Edit actions
	 */

	public AbstractAction undoAction = new UndoAction();
	public AbstractAction redoAction = new RedoAction();

	public AbstractAction cutAction = new CutAction();
	public AbstractAction copyAction = new CopyAction();
	public AbstractAction pasteAction = new PasteAction();
	public AbstractAction deleteAction = new DeleteAction();
	public AbstractAction selectAllAction = new SelectAllAction();

	public AbstractAction findPreviousAction = new FindPreviousAction();
	public AbstractAction findNextAction = new FindNextAction();
	public AbstractAction findAction = new FindAction();
	public AbstractAction replaceAction = new ReplaceAction();
	public AbstractAction goToLineAction = new GoToLineAction();

	public AbstractAction indentAction = new IndentAction();
	public AbstractAction unindentAction = new UnindentAction();

	/*
	 *  Window actions
	 */

	public AbstractAction closeWindowAction = new CloseWindowAction();
	public AbstractAction closeAllWindowsAction = new CloseAllWindowsAction();

	public AbstractAction nextWindowAction = new NextWindowAction();
	public AbstractAction previousWindowAction = new PreviousWindowAction();


	public AbstractAction runAction = new RunAction();
	public AbstractAction stepAction = new StepAction();
	public AbstractAction stopAction = new StopAction();
	public AbstractAction goAction = new GoAction();
	public AbstractAction timeUnitAction = new TimeUnitAction();

	public AbstractAction openWaveSetAction = new OpenWaveSetAction();
	public AbstractAction saveWaveSetAction = new SaveWaveSetAction();



	/*
	 * Standard constructor.
	 *
	 *
	 *  Called only once by VeriSimFrame.
	 *  When a new project is loaded via this.loadProject(), members will be reinitialized
	 *  istead of reconstructing the whole class.
	 */

	public Project(JFrame god) {
		vide.spl.showStatus("Creating project manager..");
		this.name = "no project ";
		isValid = false;
		this.god = (VeriSimFrame) god;   //the parent of all living stuff from here.
		//this.directory = null;           //remember to init this before use...
		files = new HashSet();
		editors = new Hashtable();
		documents = new Hashtable();
		lastBookmark = 0;                //sa fie acolo.(nefolosit)
		bookmarks = new Hashtable();
		vide.spl.showStatus("Creating project manager..");
		//bf = new BusyFlag();

		waveViewFrame = new WaveViewFrame(this);
		waveViewFrame.setVisible(false);
		//asta de ce p...ma-sii o adaugi aici ????    
		((VeriSimFrame)god).desktop.add(waveViewFrame, VeriSimFrame.DOCLAYER);
		//bf.start();
		watchTreeRoot = new javax.swing.tree.DefaultMutableTreeNode();
		watchTreeRoot.setUserObject(new WatchTreeNode(watchTreeRoot, WatchTreeNode.PROJECTTYPE, name));
		//todo      //ce dracu am vrut sa fac aici?
		enableEditActions(false);
		vide.spl.showStatus("Done creating project manager.");
	}

	public void error(String s) {
		message("ERROR: " + s);
	}

	public void message(String s) {
		cv.message(s);
	}

	public boolean ask(String s) {
		Object[] options = { "OK", "CANCEL" };
		int selectedValue = JOptionPane.showOptionDialog(null, s, "Question!",
				JOptionPane.DEFAULT_OPTION,
				JOptionPane.WARNING_MESSAGE,
				null, options, options[0]);
		return selectedValue == 0;
	}

	public void newProject() {
		JFileChooser chooser = new JFileChooser("New project..");
		VideFileFilter filter = new VideFileFilter("vpr", "Verilog Project");
		chooser.setFileFilter(filter);
		int returnVal = chooser.showSaveDialog(god);
		if(returnVal != JFileChooser.APPROVE_OPTION) return;
		String fileName = chooser.getSelectedFile().getPath();

		if (fileName == null) return;  //cancel => user is undecided

		File file = new File(fileName);
		if (file.exists())
			if (!ask("A project with this name\n already exists.\nOverwrite?"))
				return; //cancel  again => the user is stupid

		closeProject();

		int pindex = fileName.lastIndexOf('.');
		int slashIndex = fileName.lastIndexOf(java.io.File.separatorChar);

		if (pindex == -1) fileName = fileName + ".vpr";
		//daca userul nu a pus extensie, o adaug eu.
		pindex = fileName.lastIndexOf('.');       
		//..ca sa o scot acum..
		name = fileName.substring(slashIndex+1, pindex);  //ii scot extensia
		path = fileName.substring(0, slashIndex + 1);

		god.setTitle(name + " - vIDE");
		isValid = true;

		files.clear();
		editors.clear();
		lastBookmark = 0;
		bookmarks.clear();

		//pv.empty();   //todo
		//bv.empty();
		//activateConsole();

		saveProject();
		updateProjectView();
		//enableEditActions(true);
		enableProjectActions(true);
	}

	public void openProject() {

		JFileChooser chooser = new JFileChooser(".");
		VideFileFilter filter = new VideFileFilter(PROJECT_EXTENSION, "Verilog Project (" + PROJECT_EXTENSION + ")");
		chooser.setFileFilter(filter);
		int returnVal = chooser.showOpenDialog(god);
		if(returnVal != JFileChooser.APPROVE_OPTION) return;
		String file = chooser.getSelectedFile().getPath();
		openProject(file);
	}


	public void openProject(String file) {
		if (file == null) return; //the user is bored by this enviroment and make mistakes
		if (!(file.endsWith("." + PROJECT_EXTENSION))) {
			error("Could not load project.\nA VeriSim project file must have \n " + PROJECT_EXTENSION + " extension.");
			return;
		}

		File projectFile = new File (file);

		if (!projectFile.exists()) {
			error("Could not load project.\nFile not fonud:\n" + file);
			return;
		}

		try {
			FileInputStream fistream = new FileInputStream(file);
			ObjectInputStream oistream = new ObjectInputStream(fistream);
			if (!(((String) oistream.readObject()).equals("vIDE"))) {
				error("could not load project: bad signature.");
				return;
			}

			String version = (String) oistream.readObject();
			//todo -> check if it's the right version
			name = (String) oistream.readObject();  //nume proiect
			path = file.substring(0,
					file.lastIndexOf(java.io.File.separatorChar) +
					1);

			files.clear();
			HashSet relPaths = (HashSet) oistream.readObject();

			for (Iterator i = relPaths.iterator(); i.hasNext();) {
				String fPath = (String) i.next();
				File f;
				if (fPath.charAt(0) == '.')
					f = new File(path + fPath);
				else
					f = new File(fPath);
				if (!f.exists()) {
					error("file \"" + f.getCanonicalPath() + "\" not found. It will be removed from this project.");
					continue;
				}
				files.add(f.getCanonicalPath());
			}

			bookmarks = (Hashtable) oistream.readObject();

			fistream.close();

		} catch (Exception e) {
			System.out.println(e.toString());
			error("Project file not found.\n" + e);
		}
		isValid = true;   
		god.setTitle(name + " - vIDE");  
		updateProjectView();
		updateBookmarksView();
		enableEditActions(false);
		enableProjectActions(true);

		god.recentProjects.addName(projectFile.getPath());
		god.refreshMRU(god.recentProjectsMenu, god.recentProjects, false); 
	}

	public void saveProject() {
		try {
			if (path == null) return; //this happens when there is no project
			String filePath = path + name + "." + PROJECT_EXTENSION;
			FileOutputStream fostream = new FileOutputStream(filePath);
			ObjectOutputStream oostream = new ObjectOutputStream(fostream);
			oostream.writeObject("vIDE");        //signature
			oostream.writeObject(vide.PROJECT_VERSION);
			oostream.writeObject(name);  //nume proiect
			HashSet relPaths = new HashSet();
			for (Iterator e = files.iterator(); e.hasNext();) {
				String fullPath = (String) e.next();
				String relPath = PathConverter.toRelativePath(path, fullPath);
				relPaths.add(relPath == null ? fullPath : relPath);
				//System.out.println("converting: \"" + fullPath + "\" to \"" + relPath);
				if (relPath == null)
					message("warning: file \"" + fullPath + "\" stored with the full path");
			}
			oostream.writeObject(relPaths);
			oostream.writeObject(bookmarks);
			oostream.flush();
			fostream.close();
			message("saved \"" + filePath + "\"");
		} catch (Exception e) {
			error("failed saving project with reason:\n" + e.toString());
			System.out.println("IOException : " + e);
		}
	}

	public void closeProject() {
		//enableEditActions(false);
		enableProjectActions(false);
		//saveProject(); //you're saving it too often !
		isValid = false;   
		//todo

		//pv.setProjectName(no project);
		files.clear();// = null; 
		bookmarks.clear();// = null;

		updateProjectView();
		pv.setEnabled(false);
		wv.setEnabled(false);


		god.setTitle("no project" + " - vIDE");
		path = null;  //mark this as a non-project
		name = "no project";
	}

	public void editProject() {
		//todo
		// ???  
	}
	public void go(String msg) {
		//BUG in swing: JFrame nu se prea descurca cu BusyCursor.
		//  ..poate fi ocolit asfel:
		//god.getGlassPane().setCursor(new Cursor(Cursor.WAIT_CURSOR));
		//degeaba..
		//todo: must register a listener for the glassPane 
		//  which will block the mouse messages for a while.
		//mai bine afisez o fereastra modala goala si de dimensiuni (0,0) !!!!!
		//nu merge pt. ca blocheaza threadul apelant..
		// se poate apela pe un thread nou..
		//dar asta vrei, nu? cap sec.
		//in versiunea 2.0!
		sb.printStatus(msg);
		//bf.go();
	}
	public void stop() {
		//bf.end();
		sb.printStatus("Ready");
		//god.getGlassPane().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
		//todo -> restore cursor.
	}

	public void addFilesToProject() {

		JFileChooser chooser = new JFileChooser("Add file to project..");
		VideFileFilter filter = new VideFileFilter("v", "Verilog source file");
		chooser.setFileFilter(filter);
		int returnVal = chooser.showOpenDialog(god);
		if(returnVal != JFileChooser.APPROVE_OPTION) return;
		String fileName = chooser.getSelectedFile().getPath();
		//Voi tzine minte calea completa la fiecare fisier inclus in proiect.
		File file = new File(fileName);
		if (!file.exists()) {
			error("file \"" + fileName + "\" not found");
			return;
		}
		files.add(fileName);
		new AsyncUpdater(fileName).start();
		saveProject();
	}

	public void enableEditActions(boolean e) {
		undoAction.setEnabled(e);
		redoAction.setEnabled(e);
		cutAction.setEnabled(e);
		copyAction.setEnabled(e);
		pasteAction.setEnabled(e);
		deleteAction.setEnabled(e);
		selectAllAction.setEnabled(e);
		findPreviousAction.setEnabled(e);
		findAction.setEnabled(e);
		findNextAction.setEnabled(e);
		saveAction.setEnabled(e);
		saveAllAction.setEnabled (e);
		saveAsAction.setEnabled(e);     // de ce e comentata linia asta?
		closeAction.setEnabled(e);
		replaceAction.setEnabled(e);
		removeCurrentFileFromProject.setEnabled(e);
		revertToSavedAction.setEnabled(e);
		goToLineAction.setEnabled(e);
	}

	public void enableProjectActions(boolean e) {
		closeProjectAction.setEnabled(e);
		saveProjectAction.setEnabled(e);
		runAction.setEnabled(e);
		addFilesToProjectAction.setEnabled(e);
		wv.setEnabled(e);
	}

	public void addBookmark(String name) {
		//creates a text input dialog filled with "BookmarkX" where X = lastBookmark++
		//finds out the name of the active file and the current line and creates the value parameter
		if (focusedEditor == null) return;
		String fn = focusedEditor.getFileName();
		int ln = focusedEditor.getCurrentLine();
		String value = (fn + ":" +  ln);

		bookmarks.put(name, value);
	}

	public void removeBookmark(String name) {
		bookmarks.remove(name);
	}

	public void jumpToLocation(String fname, int lnumber) {
		Document doc = (Document)documents.get(fname);
		VeriSimDocumentFrame frame = null;
		//check to see if the requested file is already open
		if(doc == null){
			frame = openFile(fname);
		} else {
			for (Enumeration e = editors.elements(); e.hasMoreElements(); )
				if ((frame = (VeriSimDocumentFrame)e.nextElement()).editor.getDocument()
						== doc) break;
		}

		frame.jumpToLine(lnumber);
		frame.moveToFront(); //??
	}


	public void jumpToBookmark(String name) {
		String value = (String) bookmarks.get(name);
		String fname = value.substring(0, value.lastIndexOf(":"));
		int lnumber = Integer.parseInt(value.substring(value.indexOf(":")+1, value.length()));
		jumpToLocation(fname, lnumber);
		//todo bring to front.
	}

	public void revertToSaved() {
		if (!ask("Are you sure you want to reload \nlast saved version of \n" +
				focusedEditor.getFileName() + "?")) return;
		try {
			focusedEditor.loadFile();
		} catch (IOException ioex) {
			error("File read failed: " + ioex.getMessage());
		}
	}

	public void addToWindowsList(VeriSimDocumentFrame doc) {
		editors.put(doc.getTitle(), doc);
		JMenuItem mi;
		mi = god.windowMenu.add(new SelectWindowAction(god.windowMenu, doc));
		//mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK, false));
		mi.setMnemonic(("" + (doc.windowID - 5)).charAt(0));
		nextWindowAction.setEnabled(true);
		previousWindowAction.setEnabled(true);
		//System.out.println(editors + "");
		//god.addToWindowsList(doc.getTitle());

	}

	public void removeFromWindowsList(VeriSimDocumentFrame doc) {
		int ID = doc.windowID;
		int itemCount = god.windowMenu.getItemCount();
		//JMenuItem mi;


		System.out.println("removing from window list.");

		editors.remove(doc.getFileName());
		//god.windowMenu.remove(ID);
		VeriSimDocumentFrame temp;


		/*for (Enumeration e = editors.elements() ; e.hasMoreElements() ;) {
      temp = (VeriSimDocumentFrame)e.nextElement();
      if (temp.windowID > ID) {
        god.windowMenu.remove(temp.windowID);
        temp.windowID = 0;
      }
    }*/

		System.out.println("ID : " + ID);
		System.out.println("item count:" + itemCount);

		for (int i = itemCount - 1; i >= ID; --i)
			god.windowMenu.remove(ID);     //removing from the end of menu to the current ID
		boolean anyWindow = false;
		for (Enumeration e = editors.elements() ; e.hasMoreElements() ;anyWindow = true) {
			temp = (VeriSimDocumentFrame)e.nextElement();
			if (temp.windowID > ID)        //if my calculations are correct...
				addToWindowsList(temp);
		}

		if (!anyWindow) {
			nextWindowAction.setEnabled(false);
			previousWindowAction.setEnabled(false);
		}
	}

	public VeriSimDocumentFrame openFile(String fn) {
		File f = new File(fn);
		//mai gandeshte-te..
		if (!f.exists()) {
			error("Error opening file \"" + fn + "\": file not found");
			return null;
		}
		VeriSimDocumentFrame  frame;
		Document sameDoc = null;
		try {
			if ( (sameDoc = (Document)documents.get(fn)) != null)
				frame = new VeriSimDocumentFrame(this, sameDoc);
			else {
				frame = new VeriSimDocumentFrame(this, f);
				documents.put(fn, frame.editor.getDocument());
			}
			god.desktop.add(frame, VeriSimFrame.DOCLAYER);
			try {
				frame.setSelected(true);
				addToWindowsList(frame);
				god.recentFiles.addName(frame.getFileName());
				god.refreshMRU(god.recentFilesMenu, god.recentFiles, true); 
				return frame;
			}
			catch (java.beans.PropertyVetoException e2) {
				System.out.println("Exception in openFile(String) :" + e2);
				return null;
			}
		} catch (IOException ioex) {
			error("File read failed: " + ioex.getMessage());
			return null;
		}
	}

	public void openFile() {
		JFileChooser chooser = new JFileChooser("Open file..");
		VideFileFilter vfilter = new VideFileFilter("v", "Verilog source file");
		chooser.setFileFilter(vfilter);
		int returnVal = chooser.showOpenDialog(god);
		if(returnVal != JFileChooser.APPROVE_OPTION) return;
		String fileName = chooser.getSelectedFile().getPath();
		openFile(fileName);
	}

	public void newFile() {
		VeriSimDocumentFrame frame = null;
		try {
			frame = new VeriSimDocumentFrame(this, (File)null);
		} catch (IOException ioex) {}
		documents.put(frame.getFileName(), frame.editor.getDocument());
		god.desktop.add(frame, VeriSimFrame.DOCLAYER);
		try {
			frame.setSelected(true);
			addToWindowsList(frame);
		} catch (java.beans.PropertyVetoException e2) {
			System.out.println("Exception :" + e2);
		}
	}

	public void updateBookmarksView() {
		for (Enumeration e = bookmarks.keys() ; e.hasMoreElements() ;) {
			//   (String)e.nextElement();  //todo
		}
	}

	public void updateProjectView() {
		pv.clear();
		DefaultTreeModel treeModel = (DefaultTreeModel) pv.projectTree.getModel();

		if (isValid)((ProjectTreeNode)
				((DefaultMutableTreeNode)((DefaultTreeModel) treeModel).
						getRoot()).getUserObject()).name = name;
		else
			((ProjectTreeNode)((DefaultMutableTreeNode)((DefaultTreeModel) treeModel).
					getRoot()).getUserObject()).name = "No Project";

		treeModel = (DefaultTreeModel) wv.watchTree.getModel();

		if (isValid)
			((WatchTreeNode)((DefaultMutableTreeNode)((DefaultTreeModel) treeModel).
					getRoot()).getUserObject()).name = name;
		else
			((WatchTreeNode)((DefaultMutableTreeNode)((DefaultTreeModel) treeModel).
					getRoot()).getUserObject()).name = "No Project";

		new AsyncUpdater(files).start();
	}


	/**
	 * Used for asynchronously updating the project tree.
	 */
	class AsyncUpdater extends Thread{

		HashSet filez;

		AsyncUpdater(HashSet filez) {
			this.filez = filez;
		}

		AsyncUpdater(String file) {
			filez = new HashSet();
			filez.add(file);
		}

		public void run () {
			try {
				sb.initPBar();
				for (Iterator i = filez.iterator() ; i.hasNext() ;) {
					final String fName = (String)i.next();
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
							sb.adjustPBar((int)(new File(fName)).length(),
									" Parsing " + fName);
						}
					});
					pv.addFile(fName);
				}
				sb.donePBar();
				SwingUtilities.invokeAndWait(new Runnable() {
					public void run() {
						pv.invalidate();
					}
				});
			} catch (Exception ex) {
				System.out.println("exception while updating project tree: " + ex);
			}
			sb.printStatus("Ready");
		}
	}



	public File selectFile() {
		FileDialog fileDialog = new FileDialog(god);
		fileDialog.setMode(FileDialog.LOAD);
		fileDialog.show();

		String file = fileDialog.getFile();
		if (file == null)
			return null; //no file selected

		String directory = fileDialog.getDirectory();
		File f = new File(directory, file);

		if (f.exists()) return f;
		else return null;
	}

	public void removeCurrentFileFromProject () {
		String name = getCurrentEditor().getFileName();
		files.remove(name);
		pv.removeFile(name);
		god.theProject.cv.message(name + " removed from project");
		pv.invalidate();
		saveProject();
	}

	public VeriSimDocumentFrame getCurrentEditor() {  
		return focusedEditor;   //nu prea foloseshte/ focusedEditor e public shi valid tot timpul

	}

	public void saveAllFiles() {
		for (Enumeration e = editors.elements() ; e.hasMoreElements() ;) {
			VeriSimDocumentFrame df = (VeriSimDocumentFrame)e.nextElement();
			if (df.getFileData().isModified)
				try {
					df.saveFile();
				} catch (IOException ioex) {
					error("Failed saving \"" + df.getFileName() + "\": " +
							ioex.getMessage());
				}
				message(df.getFileName() + " saved.");
		}
	}

	/**
	 * Checks whether doc is used anymore, and if not,
	 * removes it from documents, so it can be gc'ed
	 */
	void releaseDocument(Document doc) {
		boolean stillNeeded = false;
		for (Enumeration en = editors.elements(); en.hasMoreElements(); ) {
			if (((VeriSimDocumentFrame)en.nextElement()).editor.getDocument()
					== doc) {
				stillNeeded = true;
				break;
			}
		}
		if (!stillNeeded) { //the old document is not
			//reffered anymore, so remove it
			documents.remove(((FileData) doc.getProperty
					(VeriSimDocumentFrame.
							fileDataProp)).fileName);
		}
	}

	void removeVeriSimDocFrame(VeriSimDocumentFrame frame) {
		editors.remove(frame.getTitle());
		//todo: remove listeners for that gc can do the job.
		god.setTitle(name + " - vide");
		enableEditActions(false);
		releaseDocument(frame.editor.getDocument());
	}


	/*
	 *   Inner classes definitions
	 *   (not) All actions used all over. + some others 
	 *
	 */


	class NewAction extends AbstractAction {
		public NewAction() {
			super("New");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/new.gif"));
			putValue(LONG_DESCRIPTION, "Creates a new file");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("New File...");
			newFile();
			stop();
		}
	}

	class AddFilesToProjectAction extends AbstractAction {
		public AddFilesToProjectAction() {
			super("Add file to project...");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Inserts existing file(s) into project");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Adding file...");
			addFilesToProject();
			stop();
		};
	}

	class OpenAction extends AbstractAction {
		public OpenAction() {
			super("Open...");setEnabled(true);
			putValue(SMALL_ICON,   new ImageIcon(vide.baseDir + "images/open.gif"));
			putValue(LONG_DESCRIPTION, "Opens an existing document");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Opening file...");
			openFile();
			stop();
		};
	}

	class CloseAction extends AbstractAction {
		public CloseAction() {
			super("Close");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Closes the document");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//todo closeFile();
		};
	}

	class SaveAction extends AbstractAction {
		public SaveAction() {
			super("Save");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/save.gif"));
			putValue(LONG_DESCRIPTION, "Saves the document");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			String fName = focusedEditor.getFileName();
			go("Saving " + fName);
			try {
				focusedEditor.saveFile();

				if (files.contains(fName)) {
					//System.out.println("in if");    //never gets here!!!????
					//updateProjectView();
					pv.addFile(fName);
					pv.invalidate();
					pv.repaint();
				}
			} catch (IOException ioex) {
				error("Failed to save file \"" + fName + "\": " + ioex);
			} finally {
				stop();
			}
		};
	}

	class SaveAsAction extends AbstractAction {
		public SaveAsAction() {
			super("Save As...");setEnabled(false);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Save the document with a new name");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//      go("Saving... " + focusedEditor.getFileName());

			JFileChooser chooser = new JFileChooser("Saving file with a different name..");
			VideFileFilter filter = new VideFileFilter("v", "Verilog souce file");
			chooser.setFileFilter(filter);
			int returnVal = chooser.showSaveDialog(god);
			if(returnVal != JFileChooser.APPROVE_OPTION) return;
			String fileName = chooser.getSelectedFile().getPath();

			File file = new File(fileName);

			if (file.exists())
				if (!ask("This file allready exist.\nOverwrite?")) {
					stop();
					return;
				}
			if (documents.get(fileName) != null) {
				error( "File \"" + fileName + "\" already opened.\n" +
				" You should first close it.");
				return;
			}

			Document oldDoc;
			try {
				oldDoc = focusedEditor.setFileName(fileName);
				releaseDocument(oldDoc);
				documents.put(fileName, focusedEditor.editor.getDocument());
			} catch (IOException ioex) {
				error("File rename failed: " + ioex);
			}
			//stop();

			//trebuie sa bag fisierul in proiect in locul caluilalt?  //todo

		};
	}

	class SaveAllAction extends AbstractAction {
		public SaveAllAction() {
			super("SaveAll");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/saveAll.gif"));  
			putValue(LONG_DESCRIPTION, "Saves the document with a different name");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Saving all...");  //todo
			saveAllFiles();
			stop();
		};
	}


	class PrintAction extends AbstractAction {
		public PrintAction() {
			super("Print");setEnabled(false);
			putValue(SMALL_ICON, emptyIcon);  
			putValue(LONG_DESCRIPTION, "Prints the document");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//todo
		};
	}

	class PrintSetupAction extends AbstractAction {
		public PrintSetupAction() {
			super("Print Setup..");setEnabled(false);
			putValue(SMALL_ICON, emptyIcon);  
			putValue(LONG_DESCRIPTION, "Setup the print options");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//todo
		};
	}

	class CutAction extends AbstractAction {
		public CutAction() {
			super("Cut");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/cut.gif"));
			putValue(LONG_DESCRIPTION, "Cuts the selected text.");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.editor.cut();
		};
	}

	class CopyAction extends AbstractAction {
		public CopyAction() {
			super("Copy");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/copy.gif"));
			putValue(LONG_DESCRIPTION, "Copy the selected text.");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.editor.copy();
		};
	}

	class PasteAction extends AbstractAction {
		public PasteAction() {
			super("Paste");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/paste.gif"));
			putValue(LONG_DESCRIPTION, "Paste the selected text.");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.editor.paste();
		};
	}

	class DeleteAction extends AbstractAction {
		public DeleteAction() {
			super("Delete");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/delete.gif"));
			putValue(LONG_DESCRIPTION, "Deletes the selected text.");
		}

		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.editor.cut();
		};
	}

	class UndoAction extends AbstractAction {
		public UndoAction() {
			super("Undo");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/undo.gif"));
			putValue(LONG_DESCRIPTION, "Undoes the last action");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.undo();
		};
	}

	class RedoAction extends AbstractAction {
		public RedoAction() {
			super("Redo");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/redo.gif"));
			putValue(LONG_DESCRIPTION, "Redoes the previously undone action");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.redo();
		};
	}

	class SelectAllAction extends AbstractAction {
		public SelectAllAction() {
			super("Select All");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Selects the entire document");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			focusedEditor.editor.selectAll();
		};
	}


	class FindPreviousAction extends AbstractAction {
		public FindPreviousAction() {
			super("Find Previous");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/findprev.gif"));
			putValue(LONG_DESCRIPTION, "Finds the previous occurrence of the specified text");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//todo ;
		};
	}

	class FindAction extends AbstractAction {
		public FindAction() {
			super("Find...");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/find.gif"));
			putValue(LONG_DESCRIPTION, "Find the specified text.");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Find...");

			String textToFindNow = JOptionPane.showInputDialog("Text to find:");

			if(!textToFind.equals(textToFindNow)){
				fromWhereToFind = 0;
				textToFind = textToFindNow;

			}

			int n = focusedEditor.editor.getText().indexOf(textToFind,fromWhereToFind);
			if(n == -1)return;
			fromWhereToFind = n + textToFind.length();
			focusedEditor.editor.select(n,n + textToFind.length());
			stop();
		};
	}

	class ReplaceAction extends AbstractAction {
		public ReplaceAction() {
			super("Replace");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Replaces the specified with different text");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			ReplaceDialog dialog = new ReplaceDialog(god, focusedEditor);
			dialog.setVisible(true);
		};
	}

	class GoToLineAction extends AbstractAction {
		public GoToLineAction() {
			super("Go to...");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Go to line number");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			GoToLineDialog dialog = new GoToLineDialog(god);
			dialog.setVisible(true);
			if (!dialog.isValid) return;
			String line = dialog.getLineNumber();
			try {
				int nline = Integer.parseInt(line);
				focusedEditor.jumpToLine(nline);
			} catch(Exception ex){   //input is not a number.
				return;
			};
		};
	}

	class FindNextAction extends AbstractAction {
		public FindNextAction() {
			super("Find Next");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/findnext.gif"));
			putValue(LONG_DESCRIPTION, "Finds the next occurrence of the specified text");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {

			int n = focusedEditor.editor.getText().indexOf(textToFind,fromWhereToFind);
			if (n == -1) {
				JOptionPane.showMessageDialog(god, "No more matches for specified text");
				fromWhereToFind = 0;
				return;
			}
			fromWhereToFind = n + textToFind.length();;
			focusedEditor.editor.select(n,n + textToFind.length());
		};
	}

	class SaveProjectAction extends AbstractAction {
		public SaveProjectAction() {
			super("Save project");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Saves the project");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Saving Project...");
			saveProject();
			stop();
		};
	}

	class NextWindowAction extends AbstractAction {
		public NextWindowAction() {
			super("Next");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/nextWindow.gif"));  //todo
			putValue(LONG_DESCRIPTION, "Activates the next editor window");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//god.windowMenu.enumerate ???//nextWindow();
			//  public MenuElement[] getSubElements()
			//Component[] comp = god.windowMenu.getMenuComponents();
			int toFocus;
			//System.out.println("focusedEditor ID" + focusedEditor.windowID);
			if (focusedEditor.windowID == god.windowMenu.getItemCount() - 1) 
				toFocus = 6;  //prima item din menu care desemneaza o fereastra 
			else
				toFocus = focusedEditor.windowID + 1;

			//System.out.println("itemCount:" + god.windowMenu.getItemCount() - 1);
			//System.out.println("to focus :" + toFocus);
			god.windowMenu.getItem(toFocus).doClick();
		};
	}

	class PreviousWindowAction extends AbstractAction {
		public PreviousWindowAction() {
			super("Previous");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/previousWindow.gif"));  //todo
			putValue(LONG_DESCRIPTION, "Activates the next editor window.");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			int toFocus;
			//System.out.println("focusedEditor ID" + focusedEditor.windowID);
			if (focusedEditor.windowID == 6) 
				toFocus = god.windowMenu.getItemCount() - 1; // sunt numerotate de la 0
			else
				toFocus = focusedEditor.windowID - 1;
			//System.out.println("itemCount:" + god.windowMenu.getItemCount());
			//System.out.println("to focus :" + toFocus); 
			god.windowMenu.getItem(toFocus).doClick();
		};
	}

	class SelectWindowAction extends AbstractAction {
		VeriSimDocumentFrame adoc;
		public SelectWindowAction(JMenu menu, VeriSimDocumentFrame ad) {
			super("" + (menu.getItemCount() - 5) + " " + ad.getTitle());
			setEnabled(true);
			adoc = ad;
			ad.windowID = menu.getItemCount();
			putValue(SMALL_ICON, emptyIcon);  //todo
			putValue(LONG_DESCRIPTION, "Bring to front " + ad.getTitle());
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//previousWindow();
			adoc.moveToFront();
			adoc.grabFocus();
			try {
				adoc.setSelected(true);
			} catch (Exception ex){
				error("java.beans.PropertyVetoException in setSelected(true)");
				System.out.println("" + ex);
			}
		};
	} 

	class CloseWindowAction extends AbstractAction {
		public CloseWindowAction() {
			super("Close");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);  //todo
			putValue(LONG_DESCRIPTION, "Closes the window");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//closeWindow();
		};
	}

	class CloseAllWindowsAction extends AbstractAction {
		public CloseAllWindowsAction() {
			super("Close All");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);  //todo
			putValue(LONG_DESCRIPTION, "Closes all open windows");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			//closeAllWindow();
		};
	}

	class NewProjectAction extends AbstractAction {
		public NewProjectAction() {
			super("New Project...");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);  //todo
			putValue(LONG_DESCRIPTION, "Creates a new project");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("New Project...");
			newProject();
			stop();
		}
	}

	class OpenProjectAction extends AbstractAction {
		public OpenProjectAction() {
			super("Open Project...");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Opens an existing project");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Opening Project...");
			openProject();
			stop();
		};
	}

	class CloseProjectAction extends AbstractAction {
		public CloseProjectAction() {
			super("Close Project");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Closes the project");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			go("Closing project...");
			closeProject();
			stop();
		}
	}

	class QuitAction extends AbstractAction {
		public QuitAction() {
			super("Exit");setEnabled(true);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Exit");
		}
		public void actionPerformed(java.awt.event.ActionEvent e) {
			god.quit();
		}
	}

	class RunAction extends AbstractAction {
		public RunAction() {
			super("Run");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/run.gif"));
			putValue(LONG_DESCRIPTION, "Start interpreting the current project");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			cv.clear();
			go("Running");
			enableProjectActions(false);
			runAction.setEnabled(false); //todo: more arguments.
			if (((Boolean)god.fHash.get("saveBeforeRun")).booleanValue())
				saveAllFiles();

			String[] arguments =new String[files.size() + 1];
			arguments[0] = "-sd";
			int n = 1;
			for(Iterator i = files.iterator(); i.hasNext();
			arguments[n++] = new String((String)i.next()));

			(new Execute(simulationThreadGroup, arguments)).start();
			new Thread (new Runnable() {
				public void run() {
					//here we now the parsing is done
					vcdReader = main.getVCDReader();
					stepAction.setEnabled(true);
					timeUnitAction.setEnabled(true);
					goAction.setEnabled(true);
					stopAction.setEnabled(true);
					saveWaveSetAction.setEnabled(false);
					openWaveSetAction.setEnabled(false);
					//bag din nou veriabilele ramase, da' le schimb historyu' cu ocazia asta
					Object[] waveTargets; //numele variabilelor din waveViewFrame
					waveTargets = waveViewFrame.reset();
					for(int i = 0; i < waveTargets.length ; i++){
						wv.addWaveForm((String)waveTargets[i]);
					}
				}
			}).start(); //asta ca sa eliberez firul de tratare (altfel nu-mi apar
			//mesajele in console cand fac parsingu'
		}
	}

	public class Execute extends Thread {  //de ce se cheama Execute shi nu ExecuteAction? (alec) 
		String[] arguments;                  //deaia ca nu e actiune(felix) 
		public Execute(ThreadGroup tg, String[] arguments) {             //hainumannebuni !
			super(tg, "Execute");
			this.arguments = arguments;
		}

		public void run() {
			go("Parsing...");
			try {
				main.runParser(arguments, (ScopeNode)(watchTreeRoot.getUserObject()), waveViewFrame.waveView, cv);
			} catch (Throwable th) { //isolates engine crashes
				th.printStackTrace();
				cv.message("error running simulator: " + th);
			} 
			enableProjectActions(true);
			saveWaveSetAction.setEnabled(true);
			openWaveSetAction.setEnabled(true);

			stepAction.setEnabled(false);
			timeUnitAction.setEnabled(false);
			goAction.setEnabled(false);
			stopAction.setEnabled(false);
			runAction.setEnabled(true);
			go("Ready");
		}
	}

	class StepAction extends AbstractAction {
		public StepAction() {
			super("Step");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/step.gif"));
			putValue(LONG_DESCRIPTION, "Executes one time step");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			cv.commandDispatch("step");
		}
	}

	class StopAction extends AbstractAction {
		public StopAction() {
			super("Stop");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/stop.gif"));
			putValue(LONG_DESCRIPTION, "Stop interpretor");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			cv.commandDispatch("exit");
		}
	}

	class GoAction extends AbstractAction {
		public GoAction() {
			super("Go");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/go.gif"));
			putValue(LONG_DESCRIPTION, "Free to go..Never stops..");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			cv.commandDispatch("go");

			stepAction.setEnabled(false);
			timeUnitAction.setEnabled(false);
			goAction.setEnabled(false);
			runAction.setEnabled(false);

		}
	}

	class TimeUnitAction extends AbstractAction {
		public TimeUnitAction() {
			super("TimeUnit");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/timeUnit.gif"));
			putValue(LONG_DESCRIPTION, "Executes one time unit");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			cv.commandDispatch("unit");
		}
	}

	class RemoveCurrentFileFromProject extends AbstractAction {
		public RemoveCurrentFileFromProject() {
			super("Remove Current File From Project ");setEnabled(false);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Removes current file from project.");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			removeCurrentFileFromProject();
		}
	}

	class RevertToSavedAction extends AbstractAction {
		public RevertToSavedAction() {
			super("Revert To Saved");setEnabled(false);
			putValue(SMALL_ICON, emptyIcon);
			putValue(LONG_DESCRIPTION, "Loads the last saved version of the saved file");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			revertToSaved();
		}
	}

	class OpenWaveSetAction extends AbstractAction {
		public OpenWaveSetAction() {
			super("Open WaveSet");setEnabled(true);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/timeUnit.gif"));
			putValue(LONG_DESCRIPTION, "Loads a previously saved WaveSet");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			waveViewFrame.openWaveSet();
		}
	}

	class IndentAction extends AbstractAction {
		public IndentAction() {
			super("Indent");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/indent.gif"));
			putValue(LONG_DESCRIPTION, "Indents the selected text block");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			//waveViewFrame.openWaveSet();
		}
	}

	class UnindentAction extends AbstractAction {
		public UnindentAction() {
			super("Unindent");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/unindent.gif"));
			putValue(LONG_DESCRIPTION, "Unindents the selected text block");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			//waveViewFrame.openWaveSet();
		}
	}

	class SaveWaveSetAction extends AbstractAction {
		public SaveWaveSetAction() {
			super("Save WaveSet");setEnabled(false);
			putValue(SMALL_ICON, new ImageIcon(vide.baseDir + "images/timeUnit.gif"));
			putValue(LONG_DESCRIPTION, "Saves the current WaveSet");
		}
		public void actionPerformed(java.awt.event.ActionEvent event) {
			waveViewFrame.saveWaveSet();
		}
	}
}


class BusyFlag extends Thread {
	private boolean go;
	public JProgressBar pb;
	private int direction  = 2;
	private int val = 0;

	public BusyFlag() {
		super();
		vide.spl.showStatus("Creating busy flag..");

		go = false;
	}

	public void run() {
		while(true) {
			try {sleep(1000);} catch (Exception e) {}
			while (go) {
				try {sleep(150);} catch (Exception e) {}
				val += direction;
				if ((val >= 40) || (val <= 0))
					direction = -direction;
				pb.setValue(val);
			}
			pb.setValue(val = 0);
		}
	}

	public void go() {
		val = 0;
		go = true;
		interrupt();
	}

	public void end() {
		go = false;
		interrupt();
	}

}
